package com.zzg.mybatis.generator.controller;

import com.baomidou.mybatisplus.core.enums.SqlLike;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.po.LikeTable;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zzg.mybatis.generator.model.*;
import com.zzg.mybatis.generator.util.DbUtil;
import com.zzg.mybatis.generator.util.MyStringUtils;
import com.zzg.mybatis.generator.view.AlertUtil;
import com.zzg.mybatis.generator.view.UIProgressCallback;
import java.util.Iterator;
import java.util.stream.Collectors;
import javafx.collections.FXCollections;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.apache.bcel.classfile.Code;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.develop.constant.DevelopConstant;
import org.springblade.develop.support.BladeCodeGenerator;

import java.awt.*;
import java.io.File;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

/**
 * bladex代码生成器
 */
public class BladexCodeController extends BaseFXController {

    private static final Logger _LOG = LoggerFactory.getLogger(BladexCodeController.class);


//    @FXML
//    private GridPane gridPane;

//    @FXML
//    private ChoiceBox<?> modelId;

    @FXML
    private TextField codeName;

    @FXML
    private TextField serviceName;

    @FXML
    private TextField tableName;

    @FXML
    private TextField tablePrefix;

    @FXML
    private TextField pkName;

    @FXML
    private TextField packageName;

    @FXML
    private ChoiceBox<?> templateType;

    @FXML
    private TextField webPath;

    @FXML
    private TextField apiPath;

    @FXML
    private ToggleGroup group1;

    @FXML
    private RadioButton baseMode1;

//    @FXML
//    private RadioButton baseMode2;

    @FXML
    private ToggleGroup group2;

    @FXML
    private RadioButton wrapMode1;

//    @FXML
//    private RadioButton wrapMode2;
//
    @FXML
    private ToggleGroup group3;
//
//    @FXML
//    private RadioButton feignMode1;

    @FXML
    private RadioButton feignMode2;

    @FXML
    private ToggleGroup group4;

    @FXML
    private RadioButton codeStyle1;

//    @FXML
//    private RadioButton codeStyle2;

    @FXML
    private ToggleGroup group5;

    @FXML
    private RadioButton codeType1;

    @FXML
    private TextField author;

    private DatabaseConfig selectedDatabaseConfig;
    private BladeModel bladeModel;
    private BladeCode bladeCode;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        _LOG.info("initialize");
    }

    @FXML
    public void generateCode() {
        if (StringUtils.isBlank(codeName.getText())) {
            AlertUtil.showWarnAlert("模块名不能为空");
            return;
        }
        UIProgressCallback alert = new UIProgressCallback(Alert.AlertType.INFORMATION);
        alert.show();
        try {
            BladeCodeGenerator generator = new BladeCodeGenerator();
            // 设置数据源
            generator.setDriverName(DbType.valueOf(selectedDatabaseConfig.getDbType()).getDriverClass());
            generator.setUrl(DbUtil.getConnectionUrlWithSchema(selectedDatabaseConfig));
            generator.setUsername(selectedDatabaseConfig.getUsername());
            generator.setPassword(selectedDatabaseConfig.getPassword());
            // 设置基础配置
            generator.setCodeName(codeName.getText());
            generator.setServiceName(serviceName.getText());
            generator.setPackageName(packageName.getText());
            generator.setPackageDir(apiPath.getText());
            generator.setPackageWebDir(webPath.getText());
            generator.setTablePrefix(tablePrefix.getText().split(","));
            generator.setIncludeTables(tableName.getText().split(","));
            generator.setAuthor(author.getText());
            // 设置是否继承基础业务字段
            generator.setHasSuperEntity(((RadioButton)group1.getSelectedToggle()).getText().equals("是"));
            // 设置是否开启包装器模式
            generator.setHasWrapper(((RadioButton)group2.getSelectedToggle()).getText().equals("是"));
            // 设置是否开启远程调用模式
            generator.setHasFeign(((RadioButton)group3.getSelectedToggle()).getText().equals("是"));
            // 代码风格
            generator.setCodeStyle(((RadioButton)group4.getSelectedToggle()).getText());
            // 代码类型
            generator.setCodeType(((RadioButton)group5.getSelectedToggle()).getText());
            // 设置控制器服务名前缀
            generator.setHasServiceName(Boolean.TRUE);
            // 设置基础模型
            Map<String, Object> model = Maps.newConcurrentMap();
            model.put("modelCode", codeName.getText());
            model.put("modelClass", MyStringUtils.dbStringToCamelStyle(codeName.getText()));
            model.put("modelTable", tableName.getText());
            generator.setModel(model);
            TableInfo tableInfo = getTableInfo(selectedDatabaseConfig, tableName.getText());
            List<TableField> fields = tableInfo.getFields();
            List<ModelPrototype> prototypes = convertPrototypes(fields);
            generator.setPrototypes(JsonUtil.readListMap(JsonUtil.toJson(prototypes)));

            generator.run();
            alert.done();
        } catch (Exception e) {
            _LOG.error(e.getMessage(), e);
            alert.close();
            AlertUtil.showErrorAlert(e.getMessage());
        }
    }

    @FXML
    public void openTargetFolder() {
        String projectFolder = apiPath.getText();
        try {
            Desktop.getDesktop().browse(new File(projectFolder).toURI());
        }catch (Exception e) {
            AlertUtil.showErrorAlert("打开目录失败，请检查目录是否填写正确" + e.getMessage());
        }
    }

    @FXML
    public void openTableColumnCustomizationPage() {
        if (tableName.getText() == null) {
            AlertUtil.showWarnAlert("请先在左侧选择数据库表");
            return;
        }
        SelectTableColumnController controller = (SelectTableColumnController) loadFXMLPage("定制列", FXMLPage.SELECT_TABLE_COLUMN, true);
        controller.setBladexCodeController(this);
        try {
            // If select same schema and another table, update table data
            if (!tableName.getText().equals(controller.getTableName())) {
                List<UITableColumnVO> tableColumns = DbUtil.getTableColumns(selectedDatabaseConfig, tableName.getText());
                controller.setColumnList(FXCollections.observableList(tableColumns));
                controller.setTableName(tableName.getText());
            }
            controller.showDialogStage();
        } catch (Exception e) {
            _LOG.error(e.getMessage(), e);
            AlertUtil.showErrorAlert(e.getMessage());
        }
    }

//    @FXML
//    public void saveGeneratorConfig() {
//
//    }

    public void setConfig(DatabaseConfig selectedConfig) {
        if (StringUtils.isNoneBlank(
                selectedConfig.getHost(),
                selectedConfig.getPort())) {
            _LOG.info("setConfig： {} {}", selectedConfig.getHost(), selectedConfig.getPort());
            this.selectedDatabaseConfig = selectedConfig;
        }
    }

    public void setBladeCodes(List<BladeCode> list){
        _LOG.info("setBladeCodes： {} {}");
        if(list.isEmpty()){
            return;
        }
        BladeCode bc = list.get(0);
        this.bladeCode = bc;
        codeName.setText(bc.getCodeName());
        serviceName.setText(bc.getServiceName());
        tableName.setText(bc.getTableName());
        tablePrefix.setText(bc.getTablePrefix());
        pkName.setText(bc.getPkName());
        packageName.setText(bc.getPackageName());
        author.setText(bc.getAuthor());
        apiPath.setText(bc.getApiPath());
        webPath.setText(bc.getWebPath());
        templateType.getSelectionModel().selectFirst();
        baseMode1.setSelected(bc.getBaseMode() == 2 ? true : false);
        wrapMode1.setSelected(bc.getWrapMode() == 2 ? true : false);
        feignMode2.setSelected(bc.getFeignMode() == 1 ? true : false);
        codeStyle1.setSelected(bc.getCodeStyle().equals("saber") ? true : false);
        codeType1.setSelected(bc.getCodeType().equals("boot") ? true : false);
    }

    private TableInfo getTableInfo(DatabaseConfig datasource, String tableName) {
        ConfigBuilder config = getConfigBuilder(datasource, tableName);
        List<TableInfo> tableInfoList = config.getTableInfoList();
        TableInfo tableInfo = null;
        Iterator<TableInfo> iterator = tableInfoList.stream().filter(table -> table.getName().equals(tableName)).toList().iterator();
        if (iterator.hasNext()) {
            tableInfo = iterator.next();
            if (tableName.contains(StringPool.UNDERSCORE)) {
                String entityPrefix = StringUtil.firstCharToUpper(tableName.split(StringPool.UNDERSCORE)[0]);
                String entityName = StringUtil.removePrefix(tableInfo.getEntityName(), entityPrefix);
                tableInfo.setEntityName(entityName);
            } else {
                tableInfo.setEntityName(StringUtil.firstCharToUpper(tableName));
            }
        }
        return tableInfo;
    }

    @SneakyThrows
    private ConfigBuilder getConfigBuilder(DatabaseConfig datasource, String tableName) {
        StrategyConfig.Builder builder = new StrategyConfig.Builder();
        //表前缀过滤，目前官方仅支持一个前缀，可自行修改为sys_或tb_或其他业务表前缀
        builder.likeTable(new LikeTable("t_", SqlLike.RIGHT));
        if (StringUtil.isNotBlank(tableName)) {
            builder.addInclude(tableName);
        }
        StrategyConfig strategyConfig = builder.entityBuilder()
            .naming(NamingStrategy.underline_to_camel)
            .columnNaming(NamingStrategy.underline_to_camel).build();
        String url = DbUtil.getConnectionUrlWithSchema(datasource);
        DataSourceConfig datasourceConfig = new DataSourceConfig.Builder(
            url, datasource.getUsername(), datasource.getPassword()
        ).build();
        return new ConfigBuilder(null, datasourceConfig, strategyConfig, null, null, null);
    }

    private List<ModelPrototype> convertPrototypes(List<TableField> tableFields) {
        return tableFields.stream().map(tableField -> {
            ModelPrototype prototype = new ModelPrototype();
            prototype.setJdbcName(tableField.getName());
            if (tableField.getColumnType() != null) {
                prototype.setJdbcType(tableField.getColumnType().getType());
                prototype.setPropertyType(tableField.getColumnType().getType());
            }
            prototype.setJdbcComment(tableField.getComment());
            prototype.setPropertyName(tableField.getPropertyName());
            prototype.setComponentType("input");
            prototype.setIsRequired(!tableField.getMetaInfo().isNullable() ? 1 : 0);
            prototype.setLength(tableField.getMetaInfo().getLength());
            return prototype;
        }).collect(Collectors.toList());
    }

}

